/*!
 * \file WTSLogger.h
 * \project	WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief 日志模块定义
 * 
 * \details 该文件定义了WonderTrader的统一日志系统，基于spdlog库实现。
 *          提供了多级别、多种格式的日志输出功能，支持：
 *          - 多种日志级别（DEBUG、INFO、WARN、ERROR、FATAL）
 *          - 分类日志输出（按模块分类）
 *          - 动态日志器管理
 *          - printf风格和fmt::format风格的接口
 *          - 线程安全的日志输出
 *          - 配置文件驱动的初始化
 *          
 *          日志系统采用静态单例模式，全局统一管理所有日志输出。
 */
#pragma once
#include "../Includes/WTSTypes.h"
#include "../Includes/WTSCollection.hpp"

#include <memory>
#include <sstream>
#include <thread>
#include <set>

//By Wesley @ 2022.01.05
//spdlog版本升级到1.9.2
//同时使用外部库fmt 8.1.0
#include <spdlog/spdlog.h>

/*! spdlog日志器的智能指针类型定义 */
typedef std::shared_ptr<spdlog::logger> SpdLoggerPtr;

NS_WTP_BEGIN
class ILogHandler;
class WTSVariant;
NS_WTP_END

USING_NS_WTP;

/*! 最大日志缓冲区大小 */
#define MAX_LOG_BUF_SIZE 2048

#include <fmt/printf.h>

/*!
 * \brief printf风格格式化实现
 * 
 * \tparam Args 可变参数类型包
 * \param buf 输出缓冲区
 * \param format 格式化字符串
 * \param args 可变参数
 */
template<typename... Args>
inline void fmt_print_impl(char* buf, const char* format, const Args&... args)
{
	static std::string s;
	s = std::move(fmt::sprintf(format, args...));
	memcpy(buf, s.c_str(), s.size());
	buf[s.size()] = '\0';
}

/*!
 * \brief fmt::format风格格式化实现
 * 
 * \tparam Args 可变参数类型包
 * \param buf 输出缓冲区
 * \param format 格式化字符串
 * \param args 可变参数
 */
template<typename... Args>
inline void fmt_format_impl(char* buf, const char* format, const Args&... args)
{
	memset(buf, 0, MAX_LOG_BUF_SIZE);
	fmt::format_to(buf, format, args...);
}

/*!
 * \class WTSLogger
 * \brief WonderTrader统一日志管理器
 * 
 * \details 基于spdlog实现的高性能日志系统，提供以下核心功能：
 *          
 *          **日志级别管理**：
 *          - DEBUG：调试信息，仅在调试模式下输出
 *          - INFO：一般信息，记录程序运行状态
 *          - WARN：警告信息，记录可能的问题
 *          - ERROR：错误信息，记录运行时错误
 *          - FATAL：致命错误，记录导致程序退出的错误
 *          
 *          **多种输出接口**：
 *          - printf风格：debug()、info()、warn()、error()、fatal()
 *          - fmt::format风格：debug_f()、info_f()、warn_f()、error_f()、fatal_f()
 *          - 分类日志：log_by_cat()、log_by_cat_f()
 *          - 动态日志器：log_dyn()、log_dyn_f()
 *          
 *          **高级特性**：
 *          - 线程安全：使用thread_local存储缓冲区
 *          - 配置驱动：支持JSON配置文件初始化
 *          - 性能优化：日志级别过滤，避免不必要的格式化
 *          - 内存管理：自动管理动态日志器生命周期
 *          
 * \note 该类采用静态单例模式，所有方法均为静态方法
 * \warning 使用前必须调用init()方法进行初始化
 */
class WTSLogger
{
private:
	/*!
	 * \brief DEBUG级别日志输出实现
	 * \param logger spdlog日志器
	 * \param message 日志消息
	 */
	static void debug_imp(SpdLoggerPtr logger, const char* message);
	
	/*!
	 * \brief INFO级别日志输出实现
	 * \param logger spdlog日志器
	 * \param message 日志消息
	 */
	static void info_imp(SpdLoggerPtr logger, const char* message);
	
	/*!
	 * \brief WARN级别日志输出实现
	 * \param logger spdlog日志器
	 * \param message 日志消息
	 */
	static void warn_imp(SpdLoggerPtr logger, const char* message);
	
	/*!
	 * \brief ERROR级别日志输出实现
	 * \param logger spdlog日志器
	 * \param message 日志消息
	 */
	static void error_imp(SpdLoggerPtr logger, const char* message);
	
	/*!
	 * \brief FATAL级别日志输出实现
	 * \param logger spdlog日志器
	 * \param message 日志消息
	 */
	static void fatal_imp(SpdLoggerPtr logger, const char* message);

	/*!
	 * \brief 初始化指定分类的日志器
	 * \param catName 分类名称
	 * \param cfgLogger 日志器配置
	 */
	static void initLogger(const char* catName, WTSVariant* cfgLogger);
	
	/*!
	 * \brief 获取指定名称的日志器
	 * \param logger 日志器名称
	 * \param pattern 输出模式，默认为空
	 * \return spdlog日志器智能指针
	 */
	static SpdLoggerPtr getLogger(const char* logger, const char* pattern = "");

	/*!
	 * \brief 打印消息到控制台（未初始化时使用）
	 * \param buffer 消息内容
	 */
	static void print_message(const char* buffer);

public:
	/*!
	 * \brief 直接输出原始日志消息
	 * \param ll 日志级别
	 * \param message 日志消息
	 */
	static void log_raw(WTSLogLevel ll, const char* message);

	/*!
	 * \brief 按分类输出原始日志消息
	 * \param catName 分类名称
	 * \param ll 日志级别
	 * \param message 日志消息
	 */
	static void log_raw_by_cat(const char* catName, WTSLogLevel ll, const char* message);

	/*!
	 * \brief 动态日志器输出原始消息
	 * \param patttern 输出模式
	 * \param catName 分类名称
	 * \param ll 日志级别
	 * \param message 日志消息
	 */
	static void log_dyn_raw(const char* patttern, const char* catName, WTSLogLevel ll, const char* message);

//////////////////////////////////////////////////////////////////////////
//printf风格接口
#pragma region "printf style apis"
public:
	/*!
	 * \brief DEBUG级别日志输出（printf风格）
	 * 
	 * \tparam Args 可变参数类型包
	 * \param format 格式化字符串（printf风格）
	 * \param args 可变参数列表
	 * 
	 * \details 输出DEBUG级别的日志信息，通常用于程序调试。
	 *          只有当全局日志级别为DEBUG时才会输出。
	 * 
	 * \note 该方法是线程安全的
	 * \see info(), warn(), error(), fatal()
	 */
	template<typename... Args>
	static void debug(const char* format, const Args& ...args)
	{
		if (m_logLevel > LL_DEBUG || m_bStopped)
			return;

		fmt_print_impl(m_buffer, format, args...);

		if (!m_bInited)
		{
			print_message(m_buffer);
			return;
		}

		debug_imp(m_rootLogger, m_buffer);
	}

	/*!
	 * \brief INFO级别日志输出（printf风格）
	 * 
	 * \tparam Args 可变参数类型包
	 * \param format 格式化字符串（printf风格）
	 * \param args 可变参数列表
	 * 
	 * \details 输出INFO级别的日志信息，用于记录程序的正常运行状态。
	 * 
	 * \note 该方法是线程安全的
	 * \see debug(), warn(), error(), fatal()
	 */
	template<typename... Args>
	static void info(const char* format, const Args& ...args)
	{
		if (m_logLevel > LL_INFO || m_bStopped)
			return;

		fmt_print_impl(m_buffer, format, args...);

		if (!m_bInited)
		{
			print_message(m_buffer);
			return;
		}

		info_imp(m_rootLogger, m_buffer);
	}

	/*!
	 * \brief WARN级别日志输出（printf风格）
	 * 
	 * \tparam Args 可变参数类型包
	 * \param format 格式化字符串（printf风格）
	 * \param args 可变参数列表
	 * 
	 * \details 输出WARN级别的日志信息，用于记录潜在的问题或异常情况。
	 * 
	 * \note 该方法是线程安全的
	 * \see debug(), info(), error(), fatal()
	 */
	template<typename... Args>
	static void warn(const char* format, const Args& ...args)
	{
		if (m_logLevel > LL_WARN || m_bStopped)
			return;

		fmt_print_impl(m_buffer, format, args...);

		if (!m_bInited)
		{
			print_message(m_buffer);
			return;
		}

		warn_imp(m_rootLogger, m_buffer);
	}

	/*!
	 * \brief ERROR级别日志输出（printf风格）
	 * 
	 * \tparam Args 可变参数类型包
	 * \param format 格式化字符串（printf风格）
	 * \param args 可变参数列表
	 * 
	 * \details 输出ERROR级别的日志信息，用于记录程序运行时的错误。
	 * 
	 * \note 该方法是线程安全的
	 * \see debug(), info(), warn(), fatal()
	 */
	template<typename... Args>
	static void error(const char* format, const Args& ...args)
	{
		if (m_logLevel > LL_ERROR || m_bStopped)
			return;

		fmt_print_impl(m_buffer, format, args...);

		if (!m_bInited)
		{
			print_message(m_buffer);
			return;
		}

		error_imp(m_rootLogger, m_buffer);
	}

	/*!
	 * \brief FATAL级别日志输出（printf风格）
	 * 
	 * \tparam Args 可变参数类型包
	 * \param format 格式化字符串（printf风格）
	 * \param args 可变参数列表
	 * 
	 * \details 输出FATAL级别的日志信息，用于记录导致程序无法继续运行的致命错误。
	 * 
	 * \note 该方法是线程安全的
	 * \see debug(), info(), warn(), error()
	 */
	template<typename... Args>
	static void fatal(const char* format, const Args& ...args)
	{
		if (m_logLevel > LL_FATAL || m_bStopped)
			return;

		fmt_print_impl(m_buffer, format, args...);

		if (!m_bInited)
		{
			print_message(m_buffer);
			return;
		}

		fatal_imp(m_rootLogger, m_buffer);
	}

	/*!
	 * \brief 通用日志输出（printf风格）
	 * 
	 * \tparam Args 可变参数类型包
	 * \param ll 日志级别
	 * \param format 格式化字符串（printf风格）
	 * \param args 可变参数列表
	 * 
	 * \details 根据指定的日志级别输出日志信息。
	 * 
	 * \note 该方法是线程安全的
	 * \see log_by_cat(), log_dyn()
	 */
	template<typename... Args>
	static void log(WTSLogLevel ll, const char* format, const Args& ...args)
	{
		if (m_logLevel > ll || m_bStopped)
			return;

		fmt_print_impl(m_buffer, format, args...);

		log_raw(ll, m_buffer);
	}

	/*!
	 * \brief 分类日志输出（printf风格）
	 * 
	 * \tparam Args 可变参数类型包
	 * \param catName 分类名称
	 * \param ll 日志级别
	 * \param format 格式化字符串（printf风格）
	 * \param args 可变参数列表
	 * 
	 * \details 向指定分类的日志器输出日志信息，便于按模块分类管理日志。
	 * 
	 * \note 该方法是线程安全的
	 * \see log(), log_dyn()
	 */
	template<typename... Args>
	static void log_by_cat(const char* catName, WTSLogLevel ll, const char* format, const Args& ...args)
	{
		if (m_logLevel > ll || m_bStopped)
			return;

		fmt_print_impl(m_buffer, format, args...);

		log_raw_by_cat(catName, ll, m_buffer);
	}

	/*!
	 * \brief 动态日志器输出（printf风格）
	 * 
	 * \tparam Args 可变参数类型包
	 * \param patttern 输出模式
	 * \param catName 分类名称
	 * \param ll 日志级别
	 * \param format 格式化字符串（printf风格）
	 * \param args 可变参数列表
	 * 
	 * \details 使用指定的输出模式和分类名称创建动态日志器进行输出。
	 * 
	 * \note 该方法是线程安全的
	 * \see log(), log_by_cat()
	 */
	template<typename... Args>
	static void log_dyn(const char* patttern, const char* catName, WTSLogLevel ll, const char* format, const Args& ...args)
	{
		if (m_logLevel > ll || m_bStopped)
			return;

		fmt_print_impl(m_buffer, format, args...);

		log_dyn_raw(patttern, catName, ll, m_buffer);
	}
#pragma endregion "printf style apis"

//////////////////////////////////////////////////////////////////////////
//fmt::format风格接口
#pragma region "format style apis"
public:
	/*!
	 * \brief DEBUG级别日志输出（fmt::format风格）
	 * 
	 * \tparam Args 可变参数类型包
	 * \param format 格式化字符串（fmt::format风格）
	 * \param args 可变参数列表
	 * 
	 * \details 使用fmt::format格式化输出DEBUG级别的日志信息。
	 *          相比printf风格，提供更好的类型安全性和性能。
	 * 
	 * \note 该方法是线程安全的
	 * \see info_f(), warn_f(), error_f(), fatal_f()
	 */
	template<typename... Args>
	static void debug_f(const char* format, const Args& ...args)
	{
		if (m_logLevel > LL_DEBUG || m_bStopped)
			return;

		fmt_format_impl(m_buffer, format, args...);

		if (!m_bInited)
		{
			print_message(m_buffer);
			return;
		}

		debug_imp(m_rootLogger, m_buffer);
	}

	/*!
	 * \brief INFO级别日志输出（fmt::format风格）
	 * 
	 * \tparam Args 可变参数类型包
	 * \param format 格式化字符串（fmt::format风格）
	 * \param args 可变参数列表
	 * 
	 * \details 使用fmt::format格式化输出INFO级别的日志信息。
	 * 
	 * \note 该方法是线程安全的
	 * \see debug_f(), warn_f(), error_f(), fatal_f()
	 */
	template<typename... Args>
	static void info_f(const char* format, const Args& ...args)
	{
		if (m_logLevel > LL_INFO || m_bStopped)
			return;

		fmt_format_impl(m_buffer, format, args...);

		if (!m_bInited)
		{
			print_message(m_buffer);
			return;
		}

		info_imp(m_rootLogger, m_buffer);
	}

	/*!
	 * \brief WARN级别日志输出（fmt::format风格）
	 * 
	 * \tparam Args 可变参数类型包
	 * \param format 格式化字符串（fmt::format风格）
	 * \param args 可变参数列表
	 * 
	 * \details 使用fmt::format格式化输出WARN级别的日志信息。
	 * 
	 * \note 该方法是线程安全的
	 * \see debug_f(), info_f(), error_f(), fatal_f()
	 */
	template<typename... Args>
	static void warn_f(const char* format, const Args& ...args)
	{
		if (m_logLevel > LL_WARN || m_bStopped)
			return;

		fmt_format_impl(m_buffer, format, args...);

		if (!m_bInited)
		{
			print_message(m_buffer);
			return;
		}

		warn_imp(m_rootLogger, m_buffer);
	}

	/*!
	 * \brief ERROR级别日志输出（fmt::format风格）
	 * 
	 * \tparam Args 可变参数类型包
	 * \param format 格式化字符串（fmt::format风格）
	 * \param args 可变参数列表
	 * 
	 * \details 使用fmt::format格式化输出ERROR级别的日志信息。
	 * 
	 * \note 该方法是线程安全的
	 * \see debug_f(), info_f(), warn_f(), fatal_f()
	 */
	template<typename... Args>
	static void error_f(const char* format, const Args& ...args)
	{
		if (m_logLevel > LL_ERROR || m_bStopped)
			return;

		fmt_format_impl(m_buffer, format, args...);

		if (!m_bInited)
		{
			print_message(m_buffer);
			return;
		}

		error_imp(m_rootLogger, m_buffer);
	}

	/*!
	 * \brief FATAL级别日志输出（fmt::format风格）
	 * 
	 * \tparam Args 可变参数类型包
	 * \param format 格式化字符串（fmt::format风格）
	 * \param args 可变参数列表
	 * 
	 * \details 使用fmt::format格式化输出FATAL级别的日志信息。
	 * 
	 * \note 该方法是线程安全的
	 * \see debug_f(), info_f(), warn_f(), error_f()
	 */
	template<typename... Args>
	static void fatal_f(const char* format, const Args& ...args)
	{
		if (m_logLevel > LL_FATAL || m_bStopped)
			return;

		fmt_format_impl(m_buffer, format, args...);

		if (!m_bInited)
		{
			print_message(m_buffer);
			return;
		}

		fatal_imp(m_rootLogger, m_buffer);
	}

	/*!
	 * \brief 通用日志输出（fmt::format风格）
	 * 
	 * \tparam Args 可变参数类型包
	 * \param ll 日志级别
	 * \param format 格式化字符串（fmt::format风格）
	 * \param args 可变参数列表
	 * 
	 * \details 使用fmt::format格式化根据指定的日志级别输出日志信息。
	 * 
	 * \note 该方法是线程安全的
	 * \see log_by_cat_f(), log_dyn_f()
	 */
	template<typename... Args>
	static void log_f(WTSLogLevel ll, const char* format, const Args& ...args)
	{
		if (m_logLevel > ll || m_bStopped)
			return;

		fmt_format_impl(m_buffer, format, args...);

		log_raw(ll, m_buffer);
	}

	/*!
	 * \brief 分类日志输出（fmt::format风格）
	 * 
	 * \tparam Args 可变参数类型包
	 * \param catName 分类名称
	 * \param ll 日志级别
	 * \param format 格式化字符串（fmt::format风格）
	 * \param args 可变参数列表
	 * 
	 * \details 使用fmt::format格式化向指定分类的日志器输出日志信息。
	 * 
	 * \note 该方法是线程安全的
	 * \see log_f(), log_dyn_f()
	 */
	template<typename... Args>
	static void log_by_cat_f(const char* catName, WTSLogLevel ll, const char* format, const Args& ...args)
	{
		if (m_logLevel > ll || m_bStopped)
			return;

		fmt_format_impl(m_buffer, format, args...);

		log_raw_by_cat(catName, ll, m_buffer);
	}

	/*!
	 * \brief 动态日志器输出（fmt::format风格）
	 * 
	 * \tparam Args 可变参数类型包
	 * \param patttern 输出模式
	 * \param catName 分类名称
	 * \param ll 日志级别
	 * \param format 格式化字符串（fmt::format风格）
	 * \param args 可变参数列表
	 * 
	 * \details 使用fmt::format格式化通过指定的输出模式和分类名称创建动态日志器进行输出。
	 * 
	 * \note 该方法是线程安全的
	 * \see log_f(), log_by_cat_f()
	 */
	template<typename... Args>
	static void log_dyn_f(const char* patttern, const char* catName, WTSLogLevel ll, const char* format, const Args& ...args)
	{
		if (m_logLevel > ll || m_bStopped)
			return;

		fmt_format_impl(m_buffer, format, args...);

		log_dyn_raw(patttern, catName, ll, m_buffer);
	}
#pragma endregion "format style apis"

public:
	/*!
	 * \brief 初始化日志系统
	 * 
	 * \param propFile 配置文件路径，默认为"logcfg.json"
	 * \param isFile 是否为文件路径，默认为true；如果为false，则propFile为JSON字符串
	 * \param handler 自定义日志处理器，默认为NULL
	 * 
	 * \details 根据配置文件或JSON字符串初始化日志系统。
	 *          配置文件应包含日志级别、输出目标、格式模式等设置。
	 * 
	 * \note 该方法必须在使用其他日志方法前调用
	 * \warning 重复调用会导致之前的配置被覆盖
	 */
	static void init(const char* propFile = "logcfg.json", bool isFile = true, ILogHandler* handler = NULL);

	/*!
	 * \brief 注册自定义日志处理器
	 * 
	 * \param handler 自定义日志处理器，默认为NULL
	 * 
	 * \details 注册一个自定义的日志处理器，用于接收所有日志消息。
	 *          可用于将日志转发到其他系统或进行特殊处理。
	 */
	static void registerHandler(ILogHandler* handler = NULL);

	/*!
	 * \brief 停止日志系统
	 * 
	 * \details 停止所有日志输出，释放相关资源。
	 *          调用后所有日志方法将不再输出任何内容。
	 */
	static void stop();

	/*!
	 * \brief 释放所有动态日志器
	 * 
	 * \details 释放通过log_dyn()系列方法创建的动态日志器，
	 *          回收相关内存资源。
	 */
	static void freeAllDynLoggers();

private:
	static bool					m_bInited;      /*!< 是否已初始化标志 */
	static bool					m_bTpInited;    /*!< 线程池是否已初始化标志 */
	static bool					m_bStopped;     /*!< 是否已停止标志 */
	static ILogHandler*			m_logHandler;   /*!< 自定义日志处理器 */
	static WTSLogLevel			m_logLevel;     /*!< 全局日志级别 */

	static SpdLoggerPtr			m_rootLogger;   /*!< 根日志器 */

	typedef WTSHashMap<std::string>	LogPatterns;
	static LogPatterns*			m_mapPatterns;     /*!< 日志模式映射 */
	static std::set<std::string>	m_setDynLoggers;   /*!< 动态日志器集合 */

	static thread_local char	m_buffer[MAX_LOG_BUF_SIZE];  /*!< 线程本地日志缓冲区 */
};


